package org.dinnermate.reservation;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Vector;

import org.dinnermate.db.DBManager;
import org.dinnermate.layout.Table;

public class ReservationLogic
{
	public static final int RES_LENGTH = 1000 * 60 * 60; // each reservation is booked for one hour
	public static final int RES_INTERVAL = 1000 * 60 * 15; // reservations can only be made on 15 min intervals
	public static final int TS_POS_RANGE = 1;
	public static final int TS_NEG_RANGE = 0;
	
	// can not be instantiated
	private ReservationLogic()
	{}
	
	public static ReservationSlot findReservation( long startTime, long endTime, int numOfSeats )
	{
		try
		{
			// get tables that can fit requested reservation
			Table[] tables = DBManager.getEntityManager().find(Table.class);
			Vector<Table> bTables = new Vector<Table>(); // perfect fit
			Vector<Table> oTables = new Vector<Table>(); // ok 
			
			addTablesToVectors(tables, numOfSeats, bTables, oTables);
			
			// look through best tables
			ReservationSlot slot = lookThroughTables(bTables, startTime, endTime);
			if (slot != null)
				return slot;
			
			// look through ok tables
			slot = lookThroughTables(oTables, startTime, endTime);
			if (slot != null)
				return slot;
		}
		catch (SQLException e)
		{
			System.err.println("Could not get tables in findReservation()");
			return null;
		}
		
		return null;
	}
	
	public static ArrayList<ReservationSlot> findAllReservations( long startTime, long endTime, int numOfSeats )
	{
		try
		{
			// get tables that can fit requested reservation
			Table[] tables = DBManager.getEntityManager().find(Table.class);
			Vector<Table> bTables = new Vector<Table>(); // perfect fit
			Vector<Table> oTables = new Vector<Table>(); // ok 
			
			addTablesToVectors(tables, numOfSeats, bTables, oTables);
			oTables.addAll(bTables);
		
			ArrayList<ReservationSlot> slots = lookThroughAllTables(oTables, startTime, endTime);
			return slots;
		}
		catch (SQLException e)
		{
			System.err.println("Could not get tables in findReservation()");
			return null;
		}
	}
	
	public static void addTablesToVectors(Table[] tables, int numOfSeats, Vector<Table> bestTables, Vector<Table> okTables)
	{
		if (bestTables == null)
			bestTables = new Vector<Table>();
		if (okTables == null)
			okTables = new Vector<Table>();
		
		for (Table table : tables)
		{
			if (table.getNumOfSeats() == numOfSeats)
				bestTables.add(table);
			else if (table.getNumOfSeats() <= (numOfSeats + TS_POS_RANGE) && table.getNumOfSeats() >= (numOfSeats - TS_NEG_RANGE))
				okTables.add(table);
		}
	}
	
	private static ReservationSlot lookThroughTables( Vector<Table> tables, long startTime, long endTime )
	{
		long curSearchTime = startTime;
		while (curSearchTime <= endTime)
		{
			for (int t = 0 ; t < tables.size() ; t++)
			{
				Table curTable = tables.get(t);
				
				if (curTable.canBook(curSearchTime))
					return new ReservationSlot(curTable, curSearchTime);
			}
			
			curSearchTime += RES_INTERVAL;
		}
		
		return null;
	}
	
	// Used to return list of all reservation slots available over long period of time.
	private static ArrayList<ReservationSlot> lookThroughAllTables( Vector<Table> tables, long startTime, long endTime )
	{
		ArrayList<ReservationSlot> freeTables = new ArrayList<ReservationSlot>();
		long curSearchTime = startTime;
		
		while (curSearchTime <= endTime)
		{
			for (int t = 0 ; t < tables.size() ; t++)
			{
				Table curTable = tables.get(t);
				
				if (curTable.canBook(curSearchTime))
				{
					freeTables.add(new ReservationSlot(curTable, curSearchTime));
					break;
				}
			}
			
			curSearchTime += RES_INTERVAL;
		}
		
		return freeTables;
	}
}
